package com.heyige.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.heyige.dto.SensitiveWordDto;
import com.heyige.entity.SensitiveWord;
import com.heyige.exception.BusinessException;
import com.heyige.exception.ErrorCode;
import com.heyige.util.RedisUtil;
import com.heyige.mapper.SensitiveWordMapper;
import com.heyige.service.SensitiveWordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import static com.heyige.common.RedisConstant.SENSITIVE_WORD_LIST_CACHE_KEY;

@Slf4j
@Service
@RequiredArgsConstructor
public class SensitiveWordServiceImpl implements SensitiveWordService {

    private final SensitiveWordMapper sensitiveWordMapper;

    // 敏感词缓存
    private final Map<String, SensitiveWord> sensitiveWordCache = new ConcurrentHashMap<>();

    // 敏感词正则表达式缓存
    private final Map<String, Pattern> sensitiveWordPatternCache = new ConcurrentHashMap<>();

    // 最后更新时间
    private LocalDateTime lastUpdateTime = null;

    /**
     * 检查文本是否包含敏感词
     *
     * @param text 要检查的文本
     * @return 检查结果
     */
    @Override
    public SensitiveWordDto.CheckResult checkText(String text) {
        // 如果文本为空，直接返回
        if (text == null || text.trim().isEmpty()) {
            return new SensitiveWordDto.CheckResult();
        }

        // 加载敏感词缓存
        loadSensitiveWordCache();

        SensitiveWordDto.CheckResult result = new SensitiveWordDto.CheckResult();
        result.setOriginalText(text);
        result.setHasSensitiveWord(false);

        String processedText = text;
        List<SensitiveWordDto.MatchedWord> matchedWords = new ArrayList<>();

        // 检查每个敏感词
        for (Map.Entry<String, SensitiveWord> entry : sensitiveWordCache.entrySet()) {
            String word = entry.getKey();
            SensitiveWord sensitiveWord = entry.getValue();

            // 检查是否包含敏感词
            if (processedText.contains(word)) {
                result.setHasSensitiveWord(true);

                // 记录匹配的敏感词
                SensitiveWordDto.MatchedWord matchedWord = new SensitiveWordDto.MatchedWord();
                matchedWord.setWord(word);
                matchedWord.setCategory(sensitiveWord.getCategory());
                matchedWord.setLevel(sensitiveWord.getLevel());
                matchedWord.setAction(SensitiveWord.Action.valueOf(sensitiveWord.getAction()));

                matchedWords.add(matchedWord);

                // 根据处理方式处理敏感词
                switch (SensitiveWord.Action.valueOf(sensitiveWord.getAction())) {
                    case REPLACE:
                        processedText = processedText.replaceAll(word, sensitiveWord.getReplacement());
                        break;
                    case REJECT:
                        result.setIsRejected(true);
                        result.setRejectReason("文本包含敏感词: " + word);
                        break;
                    case WARN:
                        // 警告方式不做处理，只是记录
                        break;
                }
            }
        }

        result.setProcessedText(processedText);
        result.setMatchedWords(matchedWords);

        return result;
    }

    /**
     * 批量检查文本是否包含敏感词
     *
     * @param texts 要检查的文本列表
     * @return 检查结果列表
     */
    @Override
    public List<SensitiveWordDto.CheckResult> checkTexts(List<String> texts) {
        List<SensitiveWordDto.CheckResult> results = new ArrayList<>();

        for (String text : texts) {
            results.add(checkText(text));
        }

        return results;
    }

    /**
     * 添加敏感词
     *
     * @param request 添加请求
     * @return 敏感词信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public SensitiveWordDto.SensitiveWordResponse addSensitiveWord(SensitiveWordDto.AddRequest request) {
        // 检查敏感词是否已存在
        LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SensitiveWord::getWord, request.getWord());
        if (sensitiveWordMapper.selectOne(queryWrapper) != null) {
            throw new BusinessException(ErrorCode.SENSITIVE_WORD_ALREADY_EXISTS, "敏感词已存在");
        }

        // 创建敏感词
        SensitiveWord sensitiveWord = new SensitiveWord();
        sensitiveWord.setWord(request.getWord());
        sensitiveWord.setCategory(request.getCategory());
        sensitiveWord.setLevel(request.getLevel());
        sensitiveWord.setAction(request.getAction().name());
        sensitiveWord.setReplacement(request.getReplacement());

        sensitiveWordMapper.insert(sensitiveWord);

        // 清除缓存
        clearCache();

        return buildSensitiveWordResponse(sensitiveWord);
    }

    /**
     * 更新敏感词
     *
     * @param id      敏感词ID
     * @param request 更新请求
     * @return 敏感词信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public SensitiveWordDto.SensitiveWordResponse updateSensitiveWord(Long id, SensitiveWordDto.UpdateRequest request) {
        // 检查敏感词是否存在
        SensitiveWord sensitiveWord = sensitiveWordMapper.selectById(id);
        if (sensitiveWord == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "敏感词不存在");
        }

        // 检查敏感词是否已被其他记录使用
        if (!sensitiveWord.getWord().equals(request.getWord())) {
            LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SensitiveWord::getWord, request.getWord());
            if (sensitiveWordMapper.selectOne(queryWrapper) != null) {
                throw new BusinessException(ErrorCode.SENSITIVE_WORD_ALREADY_EXISTS, "敏感词已存在");
            }
        }

        // 更新敏感词
        sensitiveWord.setWord(request.getWord());
        sensitiveWord.setCategory(request.getCategory());
        sensitiveWord.setLevel(request.getLevel());
        if (request.getAction() != null) {
            sensitiveWord.setAction(request.getAction().name());
        }
        sensitiveWord.setReplacement(request.getReplacement());

        sensitiveWordMapper.updateById(sensitiveWord);

        // 清除缓存
        clearCache();

        return buildSensitiveWordResponse(sensitiveWord);
    }

    /**
     * 删除敏感词
     *
     * @param id 敏感词ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteSensitiveWord(Long id) {
        // 检查敏感词是否存在
        SensitiveWord sensitiveWord = sensitiveWordMapper.selectById(id);
        if (sensitiveWord == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "敏感词不存在");
        }

        // 删除敏感词
        sensitiveWordMapper.deleteById(id);

        // 清除缓存
        clearCache();

        log.info("删除敏感词: {}", sensitiveWord.getWord());
    }

    /**
     * 获取敏感词列表
     *
     * @param page 分页参数
     * @param size 分页参数
     * @return 敏感词列表
     */
    @Override
    public IPage<SensitiveWordDto.SensitiveWordResponse> getSensitiveWords(Integer page, Integer size) {
        LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(SensitiveWord::getCreatedAt);
        IPage<SensitiveWord> sensitiveWords = sensitiveWordMapper.selectPage(new Page<>(page, size), queryWrapper);
        return sensitiveWords.convert(this::buildSensitiveWordResponse);
    }

    /**
     * 根据分类获取敏感词列表
     *
     * @param category 分类
     * @param page     分页参数
     * @param size     分页参数
     * @return 敏感词列表
     */
    @Override
    public IPage<SensitiveWordDto.SensitiveWordResponse> getSensitiveWordsByCategory(String category, Integer page, Integer size) {
        LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SensitiveWord::getCategory, category)
                .eq(SensitiveWord::getIsActive, true)
                .orderByDesc(SensitiveWord::getCreatedAt);
        IPage<SensitiveWord> sensitiveWords = sensitiveWordMapper.selectPage(new Page<>(page, size), queryWrapper);
        return sensitiveWords.convert(this::buildSensitiveWordResponse);
    }

    /**
     * 获取敏感词详情
     *
     * @param id 敏感词ID
     * @return 敏感词信息
     */
    @Override
    public SensitiveWordDto.SensitiveWordResponse getSensitiveWord(Long id) {
        SensitiveWord sensitiveWord = sensitiveWordMapper.selectById(id);
        if (sensitiveWord == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "敏感词不存在");
        }

        return buildSensitiveWordResponse(sensitiveWord);
    }

    /**
     * 启用/禁用敏感词
     *
     * @param id       敏感词ID
     * @param isActive 是否启用
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setSensitiveWordActive(Long id, Boolean isActive) {
        // 检查敏感词是否存在
        SensitiveWord sensitiveWord = sensitiveWordMapper.selectById(id);
        if (sensitiveWord == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "敏感词不存在");
        }

        // 更新状态
        sensitiveWord.setIsActive(isActive);
        sensitiveWordMapper.updateById(sensitiveWord);

        // 清除缓存
        clearCache();

        log.info("{}敏感词: {}", isActive ? "启用" : "禁用", sensitiveWord.getWord());
    }

    /**
     * 批量导入敏感词
     *
     * @param request 导入请求
     * @return 导入结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public SensitiveWordDto.ImportResult importSensitiveWords(SensitiveWordDto.ImportRequest request) {
        SensitiveWordDto.ImportResult result = new SensitiveWordDto.ImportResult();
        result.setTotalCount(request.getWords().size());
        result.setSuccessCount(0);
        result.setFailureCount(0);
        result.setFailureReasons(new ArrayList<>());

        for (String word : request.getWords()) {
            try {
                // 检查敏感词是否已存在
                LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(SensitiveWord::getWord, word);
                if (sensitiveWordMapper.selectOne(queryWrapper) == null) {
                    // 创建敏感词
                    SensitiveWord sensitiveWord = new SensitiveWord();
                    sensitiveWord.setWord(word);
                    sensitiveWord.setCategory(request.getCategory());
                    sensitiveWord.setLevel(request.getLevel());
                    if (request.getAction() != null) {
                        sensitiveWord.setAction(request.getAction().name());
                    }
                    sensitiveWord.setReplacement(request.getReplacement());

                    sensitiveWordMapper.insert(sensitiveWord);
                    result.setSuccessCount(result.getSuccessCount() + 1);
                } else {
                    result.setFailureCount(result.getFailureCount() + 1);
                    result.getFailureReasons().add("敏感词已存在: " + word);
                }
            } catch (Exception e) {
                result.setFailureCount(result.getFailureCount() + 1);
                result.getFailureReasons().add("导入失败: " + word + ", 原因: " + e.getMessage());
            }
        }

        // 清除缓存
        clearCache();

        return result;
    }

    /**
     * 加载敏感词缓存
     */
    private void loadSensitiveWordCache() {
        // 检查是否需要重新加载缓存
        if (lastUpdateTime == null || sensitiveWordCache.isEmpty()) {
            reloadCache();
            return;
        }

        // 检查Redis中是否有更新标记
        String updateFlagKey = SENSITIVE_WORD_LIST_CACHE_KEY + ":update_flag";
        Object updateFlag = RedisUtil.get(updateFlagKey);

        if (updateFlag != null) {
            reloadCache();
            // 删除更新标记
            RedisUtil.delete(updateFlagKey);
            return;
        }

        // 检查是否有更新
        LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(SensitiveWord::getUpdatedAt)
                .last("LIMIT 1");
        SensitiveWord latestSensitiveWord = sensitiveWordMapper.selectOne(queryWrapper);

        if (latestSensitiveWord != null && latestSensitiveWord.getUpdatedAt() != null &&
                latestSensitiveWord.getUpdatedAt().isAfter(lastUpdateTime)) {
            reloadCache();
        }
    }

    /**
     * 重新加载缓存
     */
    private void reloadCache() {
        log.info("重新加载敏感词缓存");

        // 清空缓存
        sensitiveWordCache.clear();
        sensitiveWordPatternCache.clear();

        // 加载所有活跃的敏感词
        LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SensitiveWord::getIsActive, true)
                .orderByDesc(SensitiveWord::getCreatedAt);
        List<SensitiveWord> sensitiveWords = sensitiveWordMapper.selectList(queryWrapper);

        for (SensitiveWord sensitiveWord : sensitiveWords) {
            sensitiveWordCache.put(sensitiveWord.getWord(), sensitiveWord);

            // 创建正则表达式
            String pattern = Pattern.quote(sensitiveWord.getWord());
            sensitiveWordPatternCache.put(sensitiveWord.getWord(), Pattern.compile(pattern));
        }

        // 更新最后加载时间
        lastUpdateTime = LocalDateTime.now();

        // 缓存到Redis
        RedisUtil.set(SENSITIVE_WORD_LIST_CACHE_KEY, sensitiveWords, 2, TimeUnit.HOURS);

        log.info("敏感词缓存加载完成，共加载 {} 个敏感词", sensitiveWords.size());
    }

    /**
     * 清除缓存
     */
    private void clearCache() {
        log.info("清除敏感词缓存");

        sensitiveWordCache.clear();
        sensitiveWordPatternCache.clear();
        lastUpdateTime = null;

        // 清除Redis缓存
        RedisUtil.delete(SENSITIVE_WORD_LIST_CACHE_KEY);

        // 设置更新标记，通知其他实例需要重新加载缓存
        String updateFlagKey = SENSITIVE_WORD_LIST_CACHE_KEY + ":update_flag";
        RedisUtil.set(updateFlagKey, "true", 5, TimeUnit.MINUTES);
    }

    /**
     * 构建敏感词响应
     *
     * @param sensitiveWord 敏感词实体
     * @return 敏感词响应
     */
    private SensitiveWordDto.SensitiveWordResponse buildSensitiveWordResponse(SensitiveWord sensitiveWord) {
        SensitiveWordDto.SensitiveWordResponse response = new SensitiveWordDto.SensitiveWordResponse();
        response.setId(sensitiveWord.getId());
        response.setWord(sensitiveWord.getWord());
        response.setCategory(sensitiveWord.getCategory());
        response.setLevel(sensitiveWord.getLevel());
        response.setAction(SensitiveWord.Action.valueOf(sensitiveWord.getAction()));
        response.setReplacement(sensitiveWord.getReplacement());
        response.setIsActive(sensitiveWord.getIsActive());
        response.setCreatedAt(sensitiveWord.getCreatedAt());
        response.setUpdatedAt(sensitiveWord.getUpdatedAt());

        return response;
    }
}